抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Naught Coin

1. 题目要求

  • 1.1 NaughtCoin 是一种 ERC20 代币,而且您已经持有这些代币。问题是您只能在 10 年之后才能转移它们。您能尝试将它们转移到另一个地址,以便您可以自由使用它们吗?通过将您的代币余额变为 0 来完成此关卡。

    这可能有用

  • 1.2 题目代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol';

contract NaughtCoin is ERC20 {

// string public constant name = 'NaughtCoin';
// string public constant symbol = '0x0';
// uint public constant decimals = 18;
uint public timeLock = block.timestamp + 10 * 365 days;
uint256 public INITIAL_SUPPLY;
address public player;

constructor(address _player)
ERC20('NaughtCoin', '0x0') {
player = _player;
INITIAL_SUPPLY = 1000000 * (10**uint256(decimals()));
// _totalSupply = INITIAL_SUPPLY;
// _balances[player] = INITIAL_SUPPLY;
_mint(player, INITIAL_SUPPLY);
emit Transfer(address(0), player, INITIAL_SUPPLY);
}

function transfer(address _to, uint256 _value) override public lockTokens returns(bool) {
super.transfer(_to, _value);
}

// Prevent the initial owner from transferring tokens until the timelock has passed
modifier lockTokens() {
if (msg.sender == player) {
require(block.timestamp > timeLock);
_;
} else {
_;
}
}
}

2. 分析

  • 2.1 通过让您的代币余额为 0 来完成此级别

  • 2.2 ***tips:***constructor**. *_mint*在执行合约*emit*事件**后*Transfer*,不知道 OpenZeppelin*_mint*函数的本机实现已经是*emit*事件*Transfer*

  • 要解决这个合约,我们需要知道 ERC20 代币的 EIP(以太坊改进提案)是如何工作的,以及 OpenZeppelin 是如何实现它的(该合约使用的是 OpenZeppelin 框架库)。

    您可以从这些链接中找到所需的所有信息:

    转移代币有两种方式:

    • 通过transfer允许msg.sender直接将代币转移到recipient
    • 通过transferFrom允许外部任意sender(可能是代币本身的所有者)代表所有者将amount代币转移到recipient. 在发送这些代币之前,所有者必须已批准管理sender该数量的代币

    因为transfer方法已经overrided约定好了NaughtCoin,我们可以使用函数来规避限制transferFrom

    这是我们需要做的:

    1. 创建一个二级账户,将我们所有的代币转移到 2) 在调用之前批准我们自己管理全部代币transferFrom3) 调用transferFrom(player, secondaryAccount, token.balanceOf(player))4) 随心所欲地使用代币!
    1
    NaughtCoin`合约应该实施什么才能真正锁定我们的代币**10 年**?他们可以实现EIP-20 定义的**一个挂钩**`overriding`,称为.`transfer``_beforeTokenTransfer

    当发生任何类型的令牌传输时,将调用此挂钩:

    • mint(从地址转移0x到用户)
    • burn(从用户转移到0x地址)
    • transfer
    • transferFrom

    通过这样做,他们可以防止这种利用。

  • 2.3 参考视频 写的攻击合约

  • interface INaughtCoin {
        function player() external view returns (address);
    }
    
    contract Hack {
        function pwn(IERC20 coin) external {
            address player = INaughtCoin(address(coin)).player();
            uint bal = coin.balanceOf(player);
            coin.transferFrom(player, address(this), bal);
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7

    - 2.4 解题步骤为:

    - ```
    // 1.Deploy
    // 2.coin.approve(hack, amount)
    // 3.pwn()

3. 解题

  • 3.1 获取关卡实例地址:0x34df3070B62B46bCBc4d0a2cbCcd670109041b8a
  • 3.2 部署攻击合约 Hack
  • image-20230225114924940
  • 3.3 根据关卡实例地址 生成 IECR20 合约
  • image-20230225115022236
  • 3.4 调用IECR20 合约中的balanceOf() 函数查看当前账户余额
  • image-20230225115111286
  • 3.5 再调用IECR20 合约的approve() 函数,传入Hack 合约地址和 所查账户余额
  • image-20230225115226308
  • image-20230225115358330
  • 3.6 调用Hack 合约中的pwn() 函数 传入关卡实例
  • image-20230225115527845
  • 3.7 回到IECR20 合约中调用balanceOf() 函数查看当前账户余额
  • image-20230225115616412
  • 3.8 提交实例
  • image-20230225115707633
  • 3.9 成功!!!!

评论



政策 · 统计 | 本站使用 Volantis 主题设计